package cz.muni.fi.pa165.hauntedhouses.dao;

import cz.muni.fi.pa165.hauntedhouses.dto.AbilityType;
import cz.muni.fi.pa165.hauntedhouses.entity.Ghost;
import cz.muni.fi.pa165.hauntedhouses.entity.House;
import cz.muni.fi.pa165.hauntedhouses.util.Util;
import java.util.Collections;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.persistence.Query;
import org.springframework.stereotype.Repository;

/**
 *
 * @author Jaromír Benda (374289)
 */
@Repository
public class GhostDAOImpl implements GhostDAO{
    
    @PersistenceContext(type=PersistenceContextType.EXTENDED)
    private EntityManager em;
    
    
    public void setEntityManager(EntityManager em){
        this.em = em;
    }

    @Override
    public void create(Ghost ghost) {
        Util.validateGhost(ghost);
        if(ghost.getId() != null) {
            throw new IllegalArgumentException("This ghost is already created");
        }
        em.persist(ghost);
        em.flush();
        em.detach(ghost);
    }

    @Override
    public void update(Ghost ghost) {
        Util.validateGhost(ghost);
        if(ghost.getId() == null) {
            throw new IllegalArgumentException("This ghost doesnt exist");
        }
        em.merge(ghost);
        em.flush();
        em.detach(ghost);
    }

    @Override
    public void remove(Ghost ghost) {
        Util.validateGhost(ghost);
        if(ghost.getId() == null) {
            throw new IllegalArgumentException("This ghost doesnt exist");
        }

        Ghost ghostToRemove;
        ghostToRemove = em.find(Ghost.class, ghost.getId());
        em.remove(ghostToRemove);
    }

    @Override
    public Ghost get(Long id) {
        if(id == null) {
            throw new IllegalArgumentException("Id is null");
        }
        if(id<0) {
            throw new IllegalArgumentException("Id < 0");
        }


        em.flush();
        Ghost ght = em.find(Ghost.class, id);
        em.detach(ght);
        em.flush();
        return ght;
    }

    @Override
    public List<Ghost> findAll() {
        Query q = em.createQuery("from Ghost");  
        List resultList = q.getResultList();
        return Collections.unmodifiableList(resultList);
    }

    @Override
    public List<Ghost> findByName(String name) {
        if(name == null || name.isEmpty()) {
            throw new IllegalArgumentException("Name is null");
        }
        Query q = em.createQuery("from Ghost where name=:name");
        q.setParameter("name", name);
        List<Ghost> ghosts = q.getResultList();
        return Collections.unmodifiableList(ghosts);
    }

    @Override
    public List<Ghost> findByHouse(House house) {
        if (!(house==null)) {
            if(house.getId()==null) {
            throw new IllegalArgumentException("House is null");
            }
            Util.validateHouse(house);
        }
        Query q;
        if (house==null) {
            q = em.createQuery("from Ghost where home_id is null");
        }else {
            q = em.createQuery("from Ghost where home_id=:house");
            q.setParameter("house", house);
        }
        List<Ghost> ghosts = q.getResultList();
        return Collections.unmodifiableList(ghosts);
    }

    @Override
    public List<Ghost> findByLevel(Integer level) {
        if(level == null) {
            throw new IllegalArgumentException("level is null");
        }
        if(level<1 || level > 9) {
            throw new IllegalArgumentException("level must be from min 1 to max 9");
        }
        Query q = em.createQuery("from Ghost where lvl=:level");
        q.setParameter("level", level);
        List<Ghost> ghosts = q.getResultList();
        return Collections.unmodifiableList(ghosts);
    }

    @Override
    public List<Ghost> findByType(AbilityType type) {
        Util.validateAbilityType(type);
        Query q = em.createQuery("from Ghost where abilityType=:type");
        q.setParameter("type", type);
        List<Ghost> ghosts = q.getResultList();
        return Collections.unmodifiableList(ghosts);       
    }
}
